package fr.liglab.adele.icasa.house.factory;

import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.InstanceManager;
import org.apache.felix.ipojo.MissingHandlerException;
import org.apache.felix.ipojo.UnacceptableConfiguration;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Validate;
import org.osgi.framework.Constants;

import fr.liglab.adele.icasa.device.GenericDevice;
import fr.liglab.adele.icasa.device.light.BinaryLight;
import fr.liglab.adele.icasa.device.light.DimmerLight;
import fr.liglab.adele.icasa.device.light.Photometer;
import fr.liglab.adele.icasa.device.presence.PresenceSensor;
import fr.liglab.adele.icasa.device.presence.Speaker;
import fr.liglab.adele.icasa.device.temperature.Cooler;
import fr.liglab.adele.icasa.device.temperature.Heater;
import fr.liglab.adele.icasa.device.temperature.Thermometer;
import fr.liglab.adele.icasa.environment.SimulatedEnvironment;
import fr.liglab.adele.icasa.environment.SimulatedEnvironmentManager;
import fr.liglab.adele.icasa.house.factory.dao.GenesisDeviceDAO;

@Component
@Instantiate
@Provides
public class EnvironmentFactoryImpl implements EnvironmentFactory {

	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.environment.impl.SimulatedEnvironmentImpl)(factory.state=1))")
	private Factory environmentFactory;

	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedBinaryLightImpl)(factory.state=1))")
	private Factory lightFactory;

	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedThermometerImpl)(factory.state=1))")
	private Factory thermometerFactory;
	
	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedHeaterImpl)(factory.state=1))")
	private Factory heaterFactory;
	
	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedPresenceSensorImpl)(factory.state=1))")
	private Factory presenseSensorFactory;
	
	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedCoolerImpl)(factory.state=1))")
	private Factory coolerFactory;
	
	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedDimmerLightImpl)(factory.state=1))")
	private Factory dimmerFactory;
	
	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.device.impl.SimulatedPhotometerImpl)(factory.state=1))")
	private Factory photometerFactory;
	
	@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.house.device.impl.SimulatedSpeakerImpl)(factory.state=1))")
	private Factory speakerFactory;
	
	//@Requires(filter = "(&(factory.name=fr.liglab.adele.icasa.house.device.impl.SimulatedAudioSourceImpl)(factory.state=1))")
	//private Factory audioSourceFactory;

	private InstanceManager getGenericInstance(Factory factory,
			Dictionary<String, Object> properties) {
		InstanceManager genericInstance;
		try {
			genericInstance = (InstanceManager) factory
					.createComponentInstance(properties);
			
			//GenericDevice gd = (GenericDevice) genericInstance.getPojoObject();
			return genericInstance;
		} catch (UnacceptableConfiguration e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MissingHandlerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public GenericDevice loadDevice(String envName, GenesisDeviceDAO deviceSpec)
			throws Exception {

		final String lightname = envName + "-" + deviceSpec.getName();

		Dictionary<String, Object> lightProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);	
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> thermoProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> presenseProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> coolerProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> heaterProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> dimmerProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> photometerProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);
				put(Constants.SERVICE_DESCRIPTION,lightname);
				put("updaterThread.period", 5000l);
			}
		};
		
		Dictionary<String, Object> soundProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);	
				put(Constants.SERVICE_DESCRIPTION,lightname);
			}
		};
		
		Dictionary<String, Object> sourceProperties = new Hashtable<String, Object>() {
			{
				put(BinaryLight.DEVICE_SERIAL_NUMBER, lightname);	
				put(Constants.SERVICE_DESCRIPTION,lightname);
			}
		};

		deviceSpec.setCompName(lightname);
		
		if (deviceSpec.getClasstype() == BinaryLight.class) {	
			deviceSpec.setInstanceManager(getGenericInstance(lightFactory, lightProperties));
		} else if (deviceSpec.getClasstype() == Thermometer.class) {			
			deviceSpec.setInstanceManager(getGenericInstance(thermometerFactory, thermoProperties));
		} else if (deviceSpec.getClasstype() == PresenceSensor.class ) {
			deviceSpec.setInstanceManager(getGenericInstance(presenseSensorFactory, presenseProperties));
		}else if (deviceSpec.getClasstype() == Cooler.class ) {
			deviceSpec.setInstanceManager(getGenericInstance(coolerFactory, coolerProperties));
		}else if (deviceSpec.getClasstype() == Heater.class ) {
			deviceSpec.setInstanceManager(getGenericInstance(heaterFactory, heaterProperties));
		}else if (deviceSpec.getClasstype() == DimmerLight.class ) {
			deviceSpec.setInstanceManager(getGenericInstance(dimmerFactory, dimmerProperties));
		}else if (deviceSpec.getClasstype() == Photometer.class ) {
			deviceSpec.setInstanceManager(getGenericInstance(photometerFactory, photometerProperties));
		}else if (deviceSpec.getClasstype()==Speaker.class){
			deviceSpec.setInstanceManager(getGenericInstance(speakerFactory, soundProperties));
		}
//		else if (deviceSpec.getClasstype()==AudioSource.class){
//			deviceSpec.setInstanceManager(getGenericInstance(audioSourceFactory, sourceProperties));
//		}
		else {
			System.out.println("No implementation found for:"
					+ deviceSpec.getClasstype());
		}
		
		return deviceSpec.getObject();
	}

	public InstanceManager InitiateEnvironment(SimulatedEnvironmentManager manager,
			final String envName, List<GenesisDeviceDAO> devices)
			throws Exception {

		Map<String, GenericDevice> m = new HashMap<String, GenericDevice>();

		Dictionary<String, Object> environmentProperties = new Hashtable<String, Object>() {
			{
				put(SimulatedEnvironment.ENVIRONMENT_ID, envName);
				put(SimulatedEnvironment.PRESENCE, 5.0d);
				put(SimulatedEnvironment.VOLUME, 2.0d);
				put(SimulatedEnvironment.ILLUMINANCE, 1.0d);
				put(Constants.SERVICE_DESCRIPTION,envName);
			}
		};

		InstanceManager envGenericInstance = (InstanceManager) environmentFactory
				.createComponentInstance(environmentProperties);

		SimulatedEnvironment se = (SimulatedEnvironment) envGenericInstance
				.getPojoObject();
		se.setProperty(SimulatedEnvironment.VOLUME, 2.0d);

		for (GenesisDeviceDAO deviceGen : devices) {

			GenericDevice gd=loadDevice(envName, deviceGen);
			
			if(deviceGen.getListener()!=null)
				gd.addListener(deviceGen.getListener());
			
			manager.bindDeviceToEnvironment(deviceGen.getCompName(), envName);

		}
		
		return envGenericInstance;

	}

	@Validate
	public void start() {
	}

	@Invalidate
	public void stop() {
	}

}
